home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / infosrvr / dev / scott / WWW / NextStep / Implementation / HTStyle.m < prev    next >
Text File  |  1991-08-13  |  9KB  |  353 lines

  1. /*    Style Implementation for Hypertext            HTStyle.m
  2. **    ==================================
  3. **
  4. **    Styles allow the translation between a logical property
  5. **    of a piece of text and its physical representation.
  6. **
  7. **    A StyleSheet is a collection of styles, defining the
  8. **    translation necessary to
  9. **    represent a document. It is a linked list of styles.
  10. */
  11. #import "HTStyle.h"
  12. #import "HTUtils.h"
  13.  
  14. /*    Create a new style
  15. */
  16. HTStyle* HTStyleNew()
  17. {
  18.     HTStyle * self = malloc(sizeof(*self));
  19.     bzero(self, sizeof(*self));
  20.     self->SGMLTag = 0;
  21.     self->textGray = NX_BLACK;
  22.     self->textRGBColor = -1;        // Not used
  23.     return self;
  24. }
  25.  
  26. /*    Create a new style with a name
  27. */
  28. HTStyle* HTStyleNewNamed(const char * name)
  29. {
  30.     HTStyle * self = HTStyleNew();
  31.     StrAllocCopy(self->name, name);
  32.     return self;
  33. }
  34.  
  35.  
  36. /*    Free a style
  37. */
  38. HTStyle * HTStyleFree(HTStyle * self)
  39. {
  40.     if (self->name) free(self->name);
  41.     if (self->SGMLTag) free(self->SGMLTag);
  42.     if (self->paragraph) free(self->paragraph);
  43.     free(self);
  44.     return 0;
  45. }
  46.  
  47.  
  48. /*    Read a style from a typed stream    (without its name)
  49. **    --------------------------------
  50. **
  51. **    Reads a style with paragraph information from a stream.
  52. **    The style name is not read or written by these routines.
  53. */
  54. #define NONE_STRING "(None)"
  55.  
  56. HTStyle * HTStyleRead(HTStyle * style, NXStream * stream)
  57. {
  58.     char myTag[STYLE_NAME_LENGTH];
  59.     char fontName[STYLE_NAME_LENGTH];
  60.     NXTextStyle *p;
  61.     int    tab;
  62.     int gotpara;        /* flag: have we got a paragraph definition? */
  63.     
  64.     NXScanf(stream, "%s%i%s%f%i",
  65.     myTag,
  66.     &style->SGMLType,
  67.     fontName,
  68.     &style->fontSize,
  69.     &gotpara);
  70.     if (gotpara) {
  71.     if (!style->paragraph) {
  72.         style->paragraph = malloc(sizeof(*(style->paragraph)));
  73.         style->paragraph->tabs = 0;
  74.     }
  75.     p = style->paragraph;
  76.     NXScanf(stream, "%f%f%f%f%hd%f%f%hd",
  77.         &p->indent1st,
  78.         &p->indent2nd,
  79.         &p->lineHt,
  80.         &p->descentLine,
  81.         &p->alignment,
  82.         &style->spaceBefore,
  83.         &style->spaceAfter,
  84.         &p->numTabs);
  85.     if (p->tabs) free(p->tabs);
  86.     p->tabs = malloc(p->numTabs * sizeof(p->tabs[0]));
  87.     for (tab=0; tab < p->numTabs; tab++) {
  88.         NXScanf(stream, "%hd%f",
  89.             &p->tabs[tab].kind,
  90.             &p->tabs[tab].x);
  91.     }
  92.     } else { /* No paragraph */
  93.         if (style->paragraph) {
  94.             free(style->paragraph);
  95.             style->paragraph = 0;
  96.     }
  97.     } /* if no paragraph */
  98.     StrAllocCopy(style->SGMLTag, myTag);
  99.     if (strcmp(fontName, NONE_STRING)==0)
  100.         style->font = 0;
  101.     else
  102.         style->font = [Font newFont:fontName size:style->fontSize];
  103.     return 0;
  104. }
  105.  
  106.  
  107. /*    Write a style to a stream in a compatible way
  108. */
  109. HTStyle * HTStyleWrite(HTStyle * style, NXStream * stream)
  110. {
  111.     int tab;
  112.     NXTextStyle *p = style->paragraph;
  113.     NXPrintf(stream, "%s %i %s %f %i\n",
  114.     style->SGMLTag,
  115.     style->SGMLType,
  116.     style->font ? [style->font name] : NONE_STRING,
  117.     style->fontSize,
  118.     p!=0);
  119.  
  120.     if (p) {
  121.     NXPrintf(stream, "\t%f %f %f %f %i %f %f\t%i\n",
  122.         p->indent1st,
  123.         p->indent2nd,
  124.         p->lineHt,
  125.         p->descentLine,
  126.         p->alignment,
  127.         style->spaceBefore,
  128.         style->spaceAfter,
  129.         p->numTabs);
  130.         
  131.     for (tab=0; tab < p->numTabs; tab++)
  132.         NXPrintf(stream, "\t%i %f\n",
  133.             p->tabs[tab].kind,
  134.             p->tabs[tab].x);
  135.     }
  136.     return style;
  137. }
  138.  
  139.  
  140. /*    Write a style to stdout for diagnostics
  141. */
  142. HTStyle * HTStyleDump(HTStyle * style)
  143. {
  144.     int tab;
  145.     NXTextStyle *p = style->paragraph;
  146.     printf("Style %i `%s' SGML:%s, type=%i. Font %s %.1f point.\n",
  147.         style,
  148.     style->name,
  149.     style->SGMLTag,
  150.     style->SGMLType,
  151.     [style->font name],
  152.     style->fontSize);
  153.     if (p) {
  154.         printf(
  155.         "\tIndents: first=%.0f others=%.0f, Height=%.1f Desc=%.1f\n"
  156.     "\tAlign=%i, %i tabs. (%.0f before, %.0f after)\n",
  157.         p->indent1st,
  158.         p->indent2nd,
  159.         p->lineHt,
  160.         p->descentLine,
  161.         p->alignment,
  162.         p->numTabs,
  163.         style->spaceBefore,
  164.         style->spaceAfter);
  165.         
  166.     for (tab=0; tab < p->numTabs; tab++) {
  167.         printf("\t\tTab kind=%i at %.0f\n",
  168.             p->tabs[tab].kind,
  169.             p->tabs[tab].x);
  170.         }
  171.     printf("\n");
  172.     } /* if paragraph */
  173.     return style;
  174. }
  175.  
  176.  
  177. /*            StyleSheet Functions
  178. **            ====================
  179. */
  180.  
  181. /*    Searching for styles:
  182. */
  183. HTStyle * HTStyleNamed(HTStyleSheet * self, const char * name)
  184. {
  185.     HTStyle * scan;
  186.     for (scan=self->styles; scan; scan=scan->next)
  187.         if (0==strcmp(scan->name, name)) return scan;
  188.     if (TRACE) printf("StyleSheet: No style named `%s'\n", name);
  189.     return 0;
  190. }
  191.  
  192. HTStyle * HTStyleForParagraph(HTStyleSheet * self, NXTextStyle *para)
  193. {
  194.     HTStyle * scan;
  195.     for (scan=self->styles; scan; scan=scan->next)
  196.         if (scan->paragraph == para) return scan;
  197.     return 0;
  198. }
  199.  
  200. /*    Find the style which best fits a given run
  201. **    ------------------------------------------
  202. **
  203. **    This heuristic is used for guessing the style for a run of
  204. **    text which has been pasted in. In order, we try:
  205. **
  206. **    A style whose paragraph structure is actually used by the run.
  207. **    A style matching in font
  208. **    A style matching in paragraph style exactly
  209. **    A style matching in paragraph to a degree
  210. */
  211. HTStyle * HTStyleForRun(HTStyleSheet *self, NXRun *run)
  212. {
  213.     HTStyle * scan;
  214.     HTStyle * best = 0;
  215.     int    bestMatch = 0;
  216.     NXTextStyle * rp = run->paraStyle;
  217.     for (scan=self->styles; scan; scan=scan->next)
  218.         if (scan->paragraph == run->paraStyle) return scan;    /* Exact */
  219.  
  220.     for (scan=self->styles; scan; scan=scan->next){
  221.         NXTextStyle * sp = scan->paragraph;
  222.         if (sp) {
  223.         int match = 0;
  224.         if (sp->indent1st ==    rp->indent1st)    match = match+1;
  225.         if (sp->indent2nd ==    rp->indent2nd)    match = match+2;
  226.         if (sp->lineHt ==        rp->lineHt)    match = match+1;
  227.         if (sp->numTabs ==        rp->numTabs)    match = match+1;
  228.         if (sp->alignment ==    rp->alignment)    match = match+3;
  229.         if (scan->font ==        run->font)    match = match+10;
  230.         if (match>bestMatch) {
  231.             best=scan;
  232.             bestMatch=match;
  233.         }
  234.     }
  235.     }
  236.     if (TRACE) printf("HTStyleForRun: Best match for style is %i out of 18\n",
  237.                  bestMatch);
  238.     return best;
  239. }
  240.  
  241.  
  242.  
  243. /*    Add a style to a sheet
  244. **    ----------------------
  245. */
  246. HTStyleSheet * HTStyleSheetAddStyle(HTStyleSheet * self, HTStyle * style)
  247. {
  248.     style->next = 0;        /* The style will go on the end */
  249.     if (!self->styles) {
  250.         self->styles = style;
  251.     } else {
  252.         HTStyle * scan;
  253.         for(scan=self->styles; scan->next; scan=scan->next); /* Find end */
  254.     scan->next=style;
  255.     }
  256.     return self;
  257. }
  258.  
  259.  
  260. /*    Remove the given object from a style sheet if it exists
  261. */
  262. HTStyleSheet * HTStyleSheetRemoveStyle(HTStyleSheet * self, HTStyle * style)
  263. {
  264.     if (self->styles = style) {
  265.         self->styles = style->next;
  266.     return self;
  267.     } else {
  268.         HTStyle * scan;
  269.     for(scan = self->styles; scan; scan = scan->next) {
  270.         if (scan->next = style) {
  271.             scan->next = style->next;
  272.         return self;
  273.         }
  274.     }
  275.     }
  276.     return 0;
  277. }
  278.  
  279. /*    Create new style sheet
  280. */
  281.  
  282. HTStyleSheet * HTStyleSheetNew()
  283. {
  284.     HTStyleSheet * self = malloc(sizeof(*self));
  285.     bzero(self, sizeof(*self));
  286.     return self;
  287. }
  288.  
  289.  
  290. /*    Free off a style sheet pointer
  291. */
  292. HTStyleSheet * HTStyleSheetFree(HTStyleSheet * self)
  293. {
  294.     HTStyle * style;
  295.     while((style=self->styles)!=0) {
  296.         self->styles = style->next;
  297.     HTStyleFree(style);
  298.     }
  299.     free(self);
  300.     return 0;
  301. }
  302.  
  303.  
  304. /*    Read a stylesheet from a typed stream
  305. **    -------------------------------------
  306. **
  307. **    Reads a style sheet from a stream.  If new styles have the same names
  308. **    as existing styles, they replace the old ones without changing the ids.
  309. */
  310.  
  311. HTStyleSheet * HTStyleSheetRead(HTStyleSheet * self, NXStream * stream)
  312. {
  313.     int numStyles;
  314.     int i;
  315.     HTStyle * style;
  316.     char styleName[80];
  317.     NXScanf(stream, " %i ", &numStyles);
  318.     if (TRACE) printf("Stylesheet: Reading %i styles\n", numStyles);
  319.     for (i=0; i<numStyles; i++) {
  320.         NXScanf(stream, "%s", styleName);
  321.         style = HTStyleNamed(self, styleName);
  322.     if (!style) {
  323.         style = HTStyleNewNamed(styleName);
  324.         (void) HTStyleSheetAddStyle(self, style);
  325.     }
  326.     (void) HTStyleRead(style, stream);
  327.     if (TRACE) HTStyleDump(style);
  328.     }
  329.     return self;
  330. }
  331.  
  332. /*    Write a stylesheet to a typed stream
  333. **    ------------------------------------
  334. **
  335. **    Writes a style sheet to a stream.
  336. */
  337.  
  338. HTStyleSheet * HTStyleSheetWrite(HTStyleSheet * self, NXStream * stream)
  339. {
  340.     int numStyles = 0;
  341.     HTStyle * style;
  342.     
  343.     for(style=self->styles; style; style=style->next) numStyles++;
  344.     NXPrintf(stream, "%i\n", numStyles);
  345.     
  346.     if (TRACE) printf("StyleSheet: Writing %i styles\n", numStyles);
  347.     for (style=self->styles; style; style=style->next) {
  348.         NXPrintf(stream, "%s ", style->name);
  349.     (void) HTStyleWrite(style, stream);
  350.     }
  351.     return self;
  352. }
  353.